﻿using System;
using vJine.Core.IoC;
using System.Text;
using System.Threading;
using System.IO;

namespace vJine.Core.IO {
    public class DataBuffer : Stream {
        public DataBuffer()
            : this(4096) {
        }

        public DataBuffer(int capacity)
            : this(capacity, null) {
        }

        public DataBuffer(int capacity, Exec<byte[], int, bool> on_full) {
            this.Capacity = capacity;
            this.Data = new byte[capacity];

            if (on_full != null) {
                this.OnFull += on_full;
            }
        }

        public DataBuffer(byte[] Buffer , Exec<byte[], int, bool> on_full) {
            this.Capacity = Buffer.Length;
            this.Data = Buffer;

            if(on_full != null) {
                this.OnFull += on_full;
            }
        }

        byte[] Data = null;
        int Capacity = 0, lenBuff = 0;
        public event Exec<byte[], int, bool> OnFull;

        public void Write(byte[] Data) {
            this.Write(Data, 0, Data.Length);
        }

        public void Write(byte[] Data, int len) {
            this.Write(Data, 0, len);
        }

        public override void Write(byte[] data, int offset, int count) {
            lock (this) {
                int len_Write = this.lenBuff + count;
                int times = len_Write / this.Capacity;
                if (len_Write % this.Capacity > 0) {
                    times += 1;
                }

                int len_write = 0; bool HasMoreData = false;
                for (int i = 0; i < times; i++) {
                    len_write = this.Capacity - this.lenBuff;

                    HasMoreData = count > len_write;
                    len_write = HasMoreData ? len_write : count;

                    Array.Copy(data, offset, this.Data, this.lenBuff, len_write);
                    offset += len_write; count -= len_write; this.lenBuff += len_write;

                    if (HasMoreData || len_write == this.Capacity) {
                        this.OnFull(this.Data, this.lenBuff, false);
                        this.lenBuff = 0;
                    }
                }
            }
        }

        public override void Flush() {
            lock(this) {
                if(this.lenBuff > 0) {
                    this.OnFull(this.Data, this.lenBuff, true);
                    this.lenBuff = 0;
                }
            }
        }

        public override bool CanRead {
            get { return false; }
        }

        public override bool CanSeek {
            get { return false; }
        }

        public override bool CanWrite {
            get { return true; }
        }

        public override long Length {
            get { return this.lenBuff;  }
        }

        public override long Position {
            get {
                throw new NotImplementedException();
            }
            set {
                throw new NotImplementedException();
            }
        }

        public override int Read(byte[] buffer, int offset, int count) {
            throw new NotImplementedException();
        }

        public override long Seek(long offset, SeekOrigin origin) {
            throw new NotImplementedException();
        }

        public override void SetLength(long value) {
            throw new NotImplementedException();
        }
    }
}
